import Taro from '@tarojs/taro';

// API接口基础域名地址

import { getToken, setToken as addToken } from './auth';

// 请求成功code值
const SUCCESS_CODE = '200';
const LOGIN_TIMEOUT_CODE = '401';
const BASE_URL = process.env.BASE_URL;

// 最多同时请求个数
const MAX_REQUEST_COUNT = 20;

// 设置请求依赖的TOKEN
let TOKEN = getToken();

// 请求队列
const requestQueue = {
  // 等待请求
  waitRequest: [],
  // 依赖请求
  relyRequest: [],
  // 请求中
  requestProcessing: [],

  // 添加请求
  addRequest(request) {
    const {
      params: { isRely = true }
    } = request;
    if (isRely && !TOKEN) {
      this.relyRequest.push(request);
    } else {
      this.waitRequest.push(request);
      this.doRequest();
    }
  },
  // 执行请求
  doRequest() {
    if (this.waitRequest.length && this.requestProcessing.length < MAX_REQUEST_COUNT) {
      const request = this.waitRequest.shift();
      this.requestProcessing.push(request);
      this.requestFun(request);
    }
  },
  // 请求函数
  requestFun(request) {
    const {
      resolve,
      reject,
      params: {
        url,
        data = {},
        method = 'POST',
        showLoading = true,
        isRely = true,
        loadingText = '加载中 ...',
        isHttpSame = true,
        isHandle = true,
        isForm = true
      }
    } = request;

    const $$header = {} as {
      Authorization?: string;
    };

    if (isForm) {
      $$header['content-type'] = 'application/x-www-form-urlencoded';
    }

    if (isRely) {
      $$header.Authorization = 'Bearer ' + TOKEN;
    }
    if (showLoading) {
      Taro.showLoading({ title: loadingText });
    }

    Taro.request({
      data,
      method,
      header: $$header,
      url: isHttpSame ? BASE_URL + url : url,
      success: (res) => {
        const response = res.data;
        if (isHandle) {
          if (response.status === SUCCESS_CODE) {
            resolve(response.data);
          } else if (response.status === LOGIN_TIMEOUT_CODE) {
            setTimeout(() => {
              Taro.showToast({
                title: '登入失效，请重新进入小程序。',
                icon: 'none',
                duration: 5000
              });
            }, 200);
            reject(response);
          } else {
            console.error('http response :>> ', response);
            setTimeout(() => {
              Taro.showToast({
                title: response.msg || response.console || '服务器异常',
                icon: 'none',
                duration: 5000
              });
            }, 200);
            reject(res);
          }
        } else {
          resolve(response);
        }
      },
      fail: (error) => {
        Taro.showToast({
          title: error.errMsg || '服务器异常',
          icon: 'none',
          duration: 5000
        });
        reject(error);
      },
      complete: () => {
        if (showLoading) Taro.hideLoading();
        this.requestProcessing.splice(this.requestProcessing.indexOf(request), 1);
        this.doRequest();
      }
    });
  }
};

interface RequestParams {
  /**
   * 请求的API地址，不包含基础域名
   */
  url: string;
  /**
   * 请求的参数
   */
  data?: StringObject | string;
  /**
   * 请求的方法，默认为POST
   */
  method?: string;
  /**
   * 加载中文案
   */
  loadingText?: string;
  /**
   * 是否依赖token
   */
  isRely?: boolean;
  /**
   * 是否使用 BASE_URL，不适用请填写完整的url地址
   */
  isHttpSame?: boolean;
  /**
   * 是否显示加载中提示，默认为true
   */
  showLoading?: boolean;
  /**
   * 是否拦截请求结果，默认为true
   */
  isHandle?: boolean;
  /**
   * 是否表单提交, 默认 json
   */
  isForm?: boolean;
}

const request = (params: RequestParams) =>
  new Promise((resolve, reject) => requestQueue.addRequest({ params, resolve, reject }));

const get = (url, param, options?: RequestParams) => {
  const extOptions = {
    showLoading: true,
    isForm: false,
    isRely: true,
    isHandle: true,
    ...options
  } as RequestParams;

  const params = {
    url,
    data: param,
    method: 'GET',
    isRely: extOptions.isRely,
    isHttpSame: extOptions.isHttpSame,
    loadingText: extOptions.loadingText,
    showLoading: extOptions.showLoading,
    isHandle: extOptions.isHandle,
    isForm: extOptions.isForm
  };
  return new Promise((resolve, reject) => requestQueue.addRequest({ params, resolve, reject }));
};

const post = (url, param, options?: RequestParams) => {
  const extOptions = {
    showLoading: true,
    isForm: false,
    isRely: true,
    isHandle: true,
    ...options
  } as RequestParams;

  const params = {
    url,
    data: param,
    method: 'POST',
    isRely: extOptions.isRely,
    isHttpSame: extOptions.isHttpSame,
    loadingText: extOptions.loadingText,
    showLoading: extOptions.showLoading,
    isHandle: extOptions.isHandle,
    isForm: extOptions.isForm
  };
  return new Promise((resolve, reject) => requestQueue.addRequest({ params, resolve, reject }));
};

// 设置TOKEN
const setToken = (token) => {
  addToken(token);
  TOKEN = token;
  const { relyRequest } = requestQueue;
  const len = relyRequest.length;
  for (let i = 0; i < len; i++) {
    requestQueue.addRequest(relyRequest[i]);
  }
  requestQueue.relyRequest = [];
};

export { request, setToken, get, post };
